﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.XPath;
using System.Web;
using System.Text.RegularExpressions;
using uForum.Businesslogic;
using uForum.Businesslogic.Services;
using uForum.Configuration;

namespace uForum.Library
{
    public class Xslt
    {

        public static void RegisterRssFeed(string url, string title, string alias)
        {
            umbraco.library.RegisterClientScriptBlock(alias, "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"" + title + "\" href=\"" + url + "\" />", false);
        }

        public static string NicePostingUrl(int pageId)
        {
            string url = umbraco.library.NiceUrl(pageId);
            if (umbraco.GlobalSettings.UseDirectoryUrls)
            {
                return url.TrimEnd('/') + ContentProperties.NewTopicTemplateAlias;
            }
            else
            {
                return url.Replace(".aspx", "/" + ContentProperties.NewTopicTemplateAlias + ".aspx");
            }
        }

        public static string NiceTopicUrl(int topicId)
        {
            Topic t = new Topic(topicId);

            if (t.Exists)
            {
                string _url = umbraco.library.NiceUrl(t.ParentId);

                if (umbraco.GlobalSettings.UseDirectoryUrls)
                {
                    return "/" + _url.Trim('/') + "/" + t.Id + "-" + t.UrlName;
                }
                else
                {
                    return "/" + _url.Substring(0, _url.LastIndexOf('.')).Trim('/') + "/" + t.Id + "-" + t.UrlName + ".aspx";
                }
            }
            else
            {
                return "";
            }
        }


        public static int CommentPageNumber(int commentId, int itemsPerPage)
        {
            Comment c = new Comment(commentId);

            int position = c.Position - 1;

            return (int)(position / itemsPerPage);
        }


        public static string NiceCommentUrl(int topicId, int commentId, int itemsPerPage)
        {
            string url = NiceTopicUrl(topicId);
            if (!string.IsNullOrEmpty(url))
            {
                Comment c = new Comment(commentId);

                int position = c.Position - 1;

                int page = (int)(position / itemsPerPage);


                url += "?p=" + page + "#comment" + c.Id;
            }

            return url;
        }


        public static XPathNodeIterator ForumPager(int forumId, int itemsPerPage, int currentPage)
        {
            XmlDocument xd = new XmlDocument();
            Forum f = new Forum(forumId);

            XmlNode pages = umbraco.xmlHelper.addTextNode(xd, "pages", "");

            int i = 0;
            int p = 0;
            while (i < (f.TotalTopics))
            {
                XmlNode page = umbraco.xmlHelper.addTextNode(xd, "page", "");
                page.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "index", p.ToString()));
                if (p == currentPage)
                {
                    page.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "current", "true"));
                }
                pages.AppendChild(page);

                p++;
                i = (i + itemsPerPage);
            }

            return pages.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator TopicPager(int topicId, int itemsPerPage, int currentPage)
        {
            XmlDocument xd = new XmlDocument();
            Topic t = new Topic(topicId);

            XmlNode pages = umbraco.xmlHelper.addTextNode(xd, "pages", "");

            int i = 0;
            int p = 0;

            while (i < (t.Replies))
            {
                XmlNode page = umbraco.xmlHelper.addTextNode(xd, "page", "");
                page.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "index", p.ToString()));
                if (p == currentPage)
                {
                    page.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "current", "true"));
                }
                pages.AppendChild(page);

                p++;
                i = (i + itemsPerPage);
            }

            return pages.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator AllForums(bool includeLatestData)
        {


            XmlDocument xd = new XmlDocument();
            XmlNode x = xd.CreateElement("forums");

            List<Businesslogic.Forum> forums = Businesslogic.Forum.Forums();
            foreach (Businesslogic.Forum f in forums)
            {
                x.AppendChild(f.ToXml(xd, includeLatestData));
            }

            return x.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator Forum(int id, bool includeLatestData)
        {
            XmlDocument xd = new XmlDocument();


            return new Forum(id).ToXml(xd, includeLatestData).CreateNavigator().Select(".");

        }

        public static XPathNodeIterator Forums(int parentId, bool includeLatestData)
        {
            XmlDocument xd = new XmlDocument();
            XmlNode x = xd.CreateElement("forums");

            List<Forum> forums = Businesslogic.Forum.Forums(parentId);
            foreach (Forum f in forums)
            {
                x.AppendChild(f.ToXml(xd, includeLatestData));
            }

            return x.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator ForumTopics(int nodeId, int amount)
        {
            XmlDocument xd = new XmlDocument();
            XmlNode x = xd.CreateElement("topics");

            List<Topic> topics = Businesslogic.Topic.TopicsInForum(nodeId, amount, 1);
            foreach (Topic t in topics)
            {
                x.AppendChild(t.ToXml(xd));
            }

            return x.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator Topic(int topicID)
        {
            XmlDocument xd = new XmlDocument();
            var t = new Topic(topicID);

            if (t.Exists)
                xd.AppendChild(t.ToXml(xd));

            return xd.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator Comment(int commentID)
        {

            XmlDocument xd = new XmlDocument();
            Comment c = new Comment(commentID);

            return c.ToXml(xd).CreateNavigator().Select(".");
        }

        public static XPathNodeIterator TopicComments(int topicID)
        {

            XmlDocument xd = new XmlDocument();
            Topic t = new Topic(topicID);

            if (t.Exists)
            {
                XmlNode comments = umbraco.xmlHelper.addTextNode(xd, "comments", "");

                foreach (Comment cc in t.Comments())
                {
                    comments.AppendChild(cc.ToXml(xd));
                }

                xd.AppendChild(comments);
            }

            return xd.CreateNavigator().Select(".");
        }

        public static XPathNodeIterator LatestTopics(int amount)
        {
            XmlDocument xd = new XmlDocument();
            XmlNode x = xd.CreateElement("topics");

            List<Topic> topics = Businesslogic.Topic.Latest(amount);
            foreach (Topic t in topics)
            {
                x.AppendChild(t.ToXml(xd));
            }

            return x.CreateNavigator().Select(".");
        }

        public static string Sanitize(string html)
        {
            return Utills.Sanitize(html);
        }

        public static string TimeDiff(string secondDate)
        {
            TimeSpan TS = DateTime.Now.Subtract(DateTime.Parse(secondDate));
            int span = int.Parse(Math.Round(TS.TotalSeconds, 0).ToString());

            if (span < 60)
                return "1 minute ago";

            if (span >= 60 && span < 3600)
                return Math.Round(TS.TotalMinutes) + " minutes ago";

            if (span >= 3600 && span < 7200)
                return "1 hour ago";

            if (span >= 3600 && span < 86400)
                return Math.Round(TS.TotalHours) + " hours ago";

            if (span >= 86400 && span < 604800)
                return Math.Round(TS.TotalDays) + " days ago";

            if (span >= 604800 && span < 1209600)
                return "1 week ago";

            if (span >= 1209600)
                return Math.Round(TS.TotalDays / 7) + " weeks ago";

            return "";
        }


        private static readonly Regex linkFinderRegex = new Regex("((http://|www\\.)([A-Z0-9.-:]{1,})\\.[0-9A-Z?;~&#=%\\-_\\./]{2,})", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
        private static readonly Regex anchorFinderRegex = new Regex("(<a(.*?)href=\"(.*?)\"(.*?)>)(.*?)(</a>)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
        private static readonly Regex preTagFinderRegex = new Regex("(<pre(.*?)>)(.*?)(</pre>)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
        private const string link = "<a rel=\"nofollow\" href=\"{0}{1}\">{2}</a>";

        public static string ResolveLinks(string body)
        {
            if (string.IsNullOrEmpty(body))
                return body;

            Dictionary<string, string> replaceValues = new Dictionary<string, string>();

            int k = 0;
            foreach (Match match in preTagFinderRegex.Matches(body))
            {
                string placeholder = string.Format("[[[[PreTagReplace{0}]]]]", k);
                body = body.Replace(match.Value, placeholder);
                replaceValues.Add(placeholder, "<pre>" + match.Groups[3].Value + "</pre>");
                k++;
            }

            int j = 0;
            foreach (Match match in anchorFinderRegex.Matches(body))
            {
                string placeholder = string.Format("[[[[AnchorReplacer{0}]]]]", j);
                body = body.Replace(match.Value, placeholder);
                if (!match.Groups[5].Value.Contains("://"))
                {
                    replaceValues.Add(placeholder, string.Format(link, string.Empty, match.Groups[3].Value, HttpUtility.UrlDecode(match.Groups[5].Value)));
                }
                else
                {
                    replaceValues.Add(placeholder, string.Format(link, string.Empty, match.Groups[3].Value, HttpUtility.UrlDecode(ShortenUrl(match.Groups[5].Value, 50))));
                }
                j++;
            }


            int i = 0;
            foreach (Match match in linkFinderRegex.Matches(body))
            {
                string placeholder = string.Format("[[[[LinkReplacer{0}]]]]", i);
                body = body.Replace(match.Value, placeholder);
                if (!match.Value.Contains("://"))
                {
                    replaceValues.Add(placeholder, string.Format(link, "http://", match.Value, HttpUtility.UrlDecode(ShortenUrl(match.Value, 50))));
                }
                else
                {
                    replaceValues.Add(placeholder, string.Format(link, string.Empty, match.Value, HttpUtility.UrlDecode(ShortenUrl(match.Value, 50))));
                }
                i++;
            }

            foreach (KeyValuePair<string, string> replaceValue in replaceValues)
            {
                body = body.Replace(replaceValue.Key, replaceValue.Value);
            }

            return body;
        }

        private static string ShortenUrl(string url, int max)
        {
            if (url.Length <= max)
                return url;

            // Remove the protocal
            int startIndex = url.IndexOf("://");
            if (startIndex > -1)
                url = url.Substring(startIndex + 3);

            if (url.Length <= max)
                return url;

            // Remove the folder structure
            int firstIndex = url.IndexOf("/") + 1;
            int lastIndex = url.LastIndexOf("/");
            if (firstIndex < lastIndex)
                url = url.Replace(url.Substring(firstIndex, lastIndex - firstIndex), "...");

            if (url.Length <= max)
                return url;

            // Remove URL parameters
            int queryIndex = url.IndexOf("?");
            if (queryIndex > -1)
                url = url.Substring(0, queryIndex);

            if (url.Length <= max)
                return url;

            // Remove URL fragment
            int fragmentIndex = url.IndexOf("#");
            if (fragmentIndex > -1)
                url = url.Substring(0, fragmentIndex);

            if (url.Length <= max)
                return url;

            // Shorten page
            firstIndex = url.LastIndexOf("/") + 1;
            lastIndex = url.LastIndexOf(".");
            if (lastIndex - firstIndex > 10)
            {
                string page = url.Substring(firstIndex, lastIndex - firstIndex);
                int length = url.Length - max + 3;
                url = url.Replace(page, "..." + page.Substring(length));
            }


            return url;
        }

        public bool CanPost()
        {
            int id = umbraco.presentation.nodeFactory.Node.GetCurrent().Id;
            return CanPost(id);
        }

        public bool CanPost(int nodeId)
        {
            AuthorizationService auth = new AuthorizationService();
            Rights rights = auth.GetRights(nodeId);
            return rights.CanPost;
        }

        public bool CanAdmin()
        {
            int id = umbraco.presentation.nodeFactory.Node.GetCurrent().Id;
            return CanAdmin(id);
        }

        public bool CanAdmin(int id)
        {
            AuthorizationService auth = new AuthorizationService();
            Rights rights = auth.GetRights(id);
            return rights.CanAdmin;
        }

        public string GetUserName(string id)
        {
            AuthorizationService auth = new AuthorizationService();
            return auth.GetUserName(id);
        }
    }
}
